<!--数据导入-->
<template>
  <div style="height: 100%">
    <el-container style="height: 100%">
      <el-aside
        width="200px"
        style="height: 100%; background-color: #f1f1f1; padding: 30px 20px"
      >
        <div style="height: 100%">
          <el-steps
            direction="vertical"
            :active="stepActive - 1"
            finish-status="success"
          >
            <el-step
              v-for="(step, index) in steps"
              :title="step.title"
              :description="step.description"
              :key="index"
            ></el-step>
          </el-steps>
        </div>
      </el-aside>
      <el-main style="padding: 10px">
        <!--第一步-->
        <el-container
          style="height: 100%"
          v-loading="fileLoading"
          v-show="stepActive === 1"
        >
          <el-header height="45px" class="pd0" style="line-height: 40px">
            <div style="float: left">
              <span style="font-size: 16px; font-weight: bold"
                >step1:{{ steps[stepActive - 1].title }}</span
              >
              <i
                style="
                  font-size: 12px;
                  color: #999999;
                  margin-left: 5px;
                  color: #f56c6c;
                "
                >第一行所有列都必须不能为空，可以为空格,否则无法看到</i
              >
            </div>
            <div style="float: right">
              <el-button
                type="primary"
                @click="funSelectFile"
                size="small"
                style="margin-right: 50px"
                :loading="fileLoading"
                >选择文件
              </el-button>
              <el-select
                v-model="sheetName"
                size="mini"
                @change="(val) => evtReadFile(null, val)"
                style="margin-right: 50px"
                placeholder="请选择Sheet"
              >
                <el-option
                  v-for="(item, index) in sheetNames"
                  :key="index"
                  :label="item"
                  :value="item"
                />
              </el-select>
              <input
                type="file"
                id="SelectFile"
                name="SelectFile"
                ref="SelectFile"
                style="display: none"
                @change="evtReadFile"
                accept=".xls,application/vnd.openxmlformats-apartmentdocument.spreadsheetml.sheet,application/vnd.ms-excel"
              />
              <el-button
                size="small"
                type="info"
                :disabled="FileData.length === 0 || stepActive !== 1"
                @click="funStepNext"
                >下一步
              </el-button>

              <el-button
                size="small"
                type="warning"
                icon="el-icon-close"
                style="font-weight: bold"
                @click="funClose"
              >
              </el-button>
            </div>
          </el-header>
          <el-main class="h100 pd0">
            <el-table
              :data="
                FileData.slice(
                  (currentPage - 1) * pagesize,
                  currentPage * pagesize
                )
              "
              border
              tooltip-effect="light"
              height="100%"
              empty-text="请选择本地文件,格式:Excel文件"
              style="width: 100%"
            >
              <!--序号-->
              <el-table-column
                v-if="FileData.length > 0"
                type="index"
                align="center"
                label="行"
                width="49"
              />
              <el-table-column
                v-for="(item, key, index) in FileData[0]"
                :key="index"
                :prop="key"
                :label="key"
              ></el-table-column>
            </el-table>
          </el-main>
          <el-footer style="height: 45px">
            <el-pagination
              style="margin-top: 10px"
              background
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
              :current-page="currentPage"
              :page-sizes="[100, 300, 500, 1000]"
              :page-size="pagesize"
              layout="total, sizes, prev, pager, next, jumper"
              :total="FileData.length"
            >
            </el-pagination>
          </el-footer>
        </el-container>
        <!--第二步-->
        <el-container style="height: 100%" v-show="stepActive === 2">
          <el-header height="45" class="pd0" style="line-height: 40px">
            <div style="float: left">
              <span style="font-size: 16px; font-weight: bold"
                >step2:{{ steps[stepActive - 1].title }}</span
              >
              <i style="font-size: 12px; color: #999999; margin-left: 5px">{{
                steps[stepActive - 1].description
              }}</i>
            </div>
            <div style="float: right">
              <el-button
                size="small"
                type="info"
                :disabled="stepActive !== 2"
                style="margin-right: 20px"
                @click="funStepUp"
                >上一步
              </el-button>
              <el-button
                size="small"
                type="primary"
                :disabled="stepActive !== 2"
                @click="funStepNext"
                >下一步
              </el-button>
            </div>
          </el-header>
          <el-main class="pd0" style="height: 100%">
            <el-table
              :data="importTargetData"
              border
              :row-class-name="evtFieldDataRowClass"
              empty-text="未配置目标数据源"
              style="width: 100%"
            >
              <!--序号-->
              <el-table-column
                type="index"
                align="center"
                label="行"
                width="49"
              />
              <el-table-column
                prop="required"
                width="50"
                align="center"
                label="必填"
              >
                <template slot-scope="scope">
                  <span
                    v-if="scope.row.required || scope.row.primaryKey"
                    style="font-size: 18px; color: red"
                    >*</span
                  >
                </template>
              </el-table-column>
              <el-table-column
                prop="required"
                width="50"
                align="center"
                label="主键"
              >
                <template slot-scope="scope">
                  <span
                    v-if="scope.row.primaryKey"
                    style="font-size: 16px; color: red"
                    >PK</span
                  >
                </template>
              </el-table-column>
              <el-table-column prop="label" label="目标数据字段">
              </el-table-column>
              <el-table-column
                prop="dataSource"
                label="源数据字段（要导入的数据）"
              >
                <template slot-scope="scope">
                  <el-select
                    v-model="scope.row.dataSource"
                    size="mini"
                    v-if="scope.row.dataSource !== '-1'"
                    placeholder="请选择源数据字段"
                  >
                    <el-option
                      v-for="(item, index) in sourceTitle"
                      :key="index"
                      :label="item.label"
                      :value="item.value"
                    />
                  </el-select>
                  <span v-else style="color: #999999">
                    {{
                      scope.row.sourceDesc
                        ? scope.row.sourceDesc
                        : "内容根据关键字段从数据库检索获取"
                    }}
                  </span>
                </template>
              </el-table-column>
            </el-table>
          </el-main>
        </el-container>
        <!--第三步-->
        <el-container
          style="height: 100%"
          v-loading="fileLoading"
          v-show="stepActive === 3"
        >
          <el-header height="45px" class="pd0" style="line-height: 40px">
            <div style="float: left">
              <span style="font-size: 16px; font-weight: bold"
                >step3:{{ steps[stepActive - 1].title }}</span
              >
              <i style="font-size: 12px; color: #999999; margin-left: 5px">{{
                steps[stepActive - 1].description
              }}</i>
            </div>
            <div style="float: right" v-if="!DataValidate">
              <span v-if="errDataCnt > 0" style="margin-right: 50px">
                共
                <b style="font-size: 16px; color: #f56c6c">{{ errDataCnt }}</b>
                条错误数据
              </span>
              <el-dropdown
                split-button
                size="small"
                trigger="click"
                type="primary"
                @click="funFilterData"
                @command="evtFilterCommand"
                style="margin-right: 30px"
                >查看全部
                <el-dropdown-menu slot="dropdown">
                  <el-dropdown-item command="ok">
                    查看正确数据
                  </el-dropdown-item>
                  <el-dropdown-item command="err" divided
                    >查看错误数据
                  </el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>
              <el-button
                size="small"
                type="info"
                style="margin-right: 20px"
                @click="funExportExcel"
                >导出数据
              </el-button>
              <el-button
                size="small"
                type="info"
                style="margin-right: 20px"
                @click="funStepUp"
                >上一步
              </el-button>
              <el-button size="small" type="primary" @click="funStepNext"
                >下一步
              </el-button>
            </div>
          </el-header>
          <el-main class="h100 pd0">
            <div v-if="DataValidate">
              <el-divider></el-divider>
              <p>{{ DataValidateMsg }}</p>
              <el-progress
                :text-inside="true"
                :stroke-width="26"
                :percentage="DataValidatePercentage"
                style="margin-top: 30px"
              ></el-progress>
            </div>
            <el-table
              v-else
              :data="
                dataList.slice(
                  (currentPage - 1) * pagesize,
                  currentPage * pagesize
                )
              "
              border
              highlight-current-row
              tooltip-effect="light"
              height="100%"
              style="width: 100%"
            >
              <!--序号-->
              <el-table-column
                type="index"
                align="center"
                label="行"
                :fixed="true"
                width="80"
              >
                <template slot-scope="scope">
                  <span v-if="scope.row.status === '0'">{{
                    scope.$index + 1
                  }}</span>
                  <span v-else style="color: #f56c6c">
                    {{ scope.$index + 1 }}
                  </span>
                </template>
              </el-table-column>
              <el-table-column
                v-for="item in importTargetData"
                :width="item.width"
                :fixed="item.fixed"
                :key="item.prop"
                :prop="item.prop"
                show-overflow-tooltip
                :label="item.label"
              ></el-table-column>
              <el-table-column label="数据结果" prop="status" width="200">
                <template slot-scope="scope">
                  <span v-if="scope.row.status === '0'">正常</span>
                  <span v-else style="color: #f56c6c">
                    {{ scope.row.status }}
                  </span>
                </template>
              </el-table-column>
            </el-table>
          </el-main>
          <el-footer v-if="!DataValidate" style="height: 45px">
            <el-pagination
              style="margin-top: 10px"
              background
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
              :current-page="currentPage"
              :page-sizes="[100, 300, 500, 1000]"
              :page-size="pagesize"
              layout="total, sizes, prev, pager, next, jumper"
              :total="dataList.length"
            >
            </el-pagination>
          </el-footer>
        </el-container>
        <!--第四步-->
        <el-container
          style="height: 100%"
          v-loading="fileLoading"
          v-show="stepActive === 4"
        >
          <el-header height="45px" class="pd0" style="line-height: 40px">
            <div style="float: left">
              <span style="font-size: 16px; font-weight: bold"
                >step4:{{ steps[stepActive - 1].title }}</span
              >
              <i style="font-size: 12px; color: #999999; margin-left: 5px">{{
                steps[stepActive - 1].description
              }}</i>
            </div>
            <div style="float: right" v-if="!importLoading">
              <el-button
                size="small"
                type="info"
                style="margin-right: 20px"
                @click="funStepUp"
                >上一步
              </el-button>
              <el-button size="small" type="primary" @click="funImportData"
                >导入数据
              </el-button>
            </div>
          </el-header>
          <el-main class="h100 pd0">
            <el-form
              ref="formEdit"
              size="small"
              label-width="120px"
              @submit.native.prevent
            >
              <el-row style="width: 70%; margin-left: 30px">
                <el-col :span="8">
                  <div class="grid-content right-line">
                    <span class="title" style="color: #409eff">
                      {{ dataListALL.length }}
                    </span>
                    <span class="msg">源数据总数</span>
                  </div>
                </el-col>
                <el-col :span="8">
                  <div class="grid-content right-line">
                    <span class="title" style="color: #f56c6c">
                      {{ errDataCnt }}
                    </span>
                    <span class="msg">源数据验证错误数据</span>
                  </div>
                </el-col>
                <el-col :span="8">
                  <div class="grid-content">
                    <span class="title" style="color: #67c23a">
                      {{ dataListALL.length - errDataCnt }}
                    </span>
                    <span class="msg">源数据验证正确数据</span>
                  </div>
                </el-col>
              </el-row>
              <el-divider></el-divider>
              <el-form-item
                label="更新方式:"
                style="font-weight: bold; font-size: 14px"
              >
                <el-radio-group v-model="updateType">
                  <el-radio
                    :label="1"
                    :disabled="updateType !== 1"
                    style="width: 100%; margin: 10px 0; font-size: 13px"
                    >返回数据
                    <i
                      style="
                        color: #999999;
                        margin-left: 10px;
                        font-weight: normal;
                        font-style: normal;
                      "
                      >不直接更新数据，返回数据给界面进行处理。</i
                    >
                  </el-radio>
                  <el-radio
                    :label="2"
                    :disabled="updateType !== 2"
                    style="width: 100%; margin: 10px 0; font-size: 13px"
                    >更新数据
                    <i
                      style="
                        color: #999999;
                        margin-left: 10px;
                        font-weight: normal;
                        font-style: normal;
                      "
                      >根据主键字段进行查找，存在则更新，不存在则追加。</i
                    >
                  </el-radio>
                  <el-radio
                    :label="3"
                    :disabled="updateType !== 3"
                    style="width: 100%; margin: 10px 0; font-size: 13px"
                    >只更新数据
                    <i
                      style="
                        color: #999999;
                        margin-left: 10px;
                        font-weight: normal;
                        font-style: normal;
                      "
                      >根据主键字段进行查找，存在则更新，不存在则跳过。</i
                    >
                  </el-radio>
                  <el-radio
                    :label="4"
                    :disabled="updateType !== 4"
                    style="width: 100%; margin: 10px 0; font-size: 13px"
                    >只追加数据
                    <i
                      style="
                        color: #999999;
                        margin-left: 10px;
                        font-weight: normal;
                        font-style: normal;
                      "
                      >根据主键字段进行查找，不存在则追加，存在则跳过。</i
                    >
                  </el-radio>
                </el-radio-group>
              </el-form-item>
            </el-form>
            <div v-if="importLoading">
              <el-divider></el-divider>
              <el-progress
                :text-inside="true"
                :stroke-width="26"
                :percentage="DataImportPercentage"
              ></el-progress>
            </div>
          </el-main>
        </el-container>
      </el-main>
    </el-container>
  </div>
</template>
<script>
import XLSX from "xlsx";

export default {
  name: "importExcel",
  data() {
    return {
      stepActive: 1,
      fileLoading: false,
      FileData: [],
      steps: [
        { title: "选择文件", description: "选择本地文件并预览原始数据" },
        { title: "数据映射", description: "目标数据与源数据建立字段映射关系" },
        {
          title: "数据验证",
          description: "根据业务逻辑进行数据验证，并返回结果",
        },
        { title: "完成导入", description: "根据配置将源数据更新到目标数据中" },
      ],
      DataValidatePercentage: 0,
      currentPage: 1,
      pagesize: 100,
      //源数据表头
      sourceTitle: [],
      updateType: this.importType === null ? 1 : this.importType,
      excelFile: null,
      sheetNames: [],
      sheetName: "",
      DataValidate: true,
      DataValidateMsg: "正在验证数据...",
      dataList: [],
      dataListALL: [],
      errDataCnt: 0,
      importLoading: false,
      DataImportPercentage: 0,
      importQuery: {},
    };
  },
  props: {
    //导入验证API
    apiImportDataValidate: null,
    apiImportData: null,
    //导入目标数据结构
    importTargetData: null,
    //导入数据类型 return  返回数据 update (更新数据、只更新、只追加）
    importType: null,
    //查询字段及查询值，例如：查询库房ID，从父级带过来的
    importQueryFiled: null,
  },
  methods: {
    //选择文件
    funSelectFile() {
      let fl = document.getElementById("SelectFile");
      if (fl) fl.click();
    },
    //读取文件内容并展示
    evtReadFile(obj, sheetName) {
      let files;
      if (obj === null) {
        files = this.excelFile;
      } else {
        files = obj.target.files[0];
        this.excelFile = files;
      }
      let reader = new FileReader();
      let jsonobject_0;
      let that = this;
      that.fileLoading = true;
      that.currentPage = 1;
      that.FileData = [];
      reader.onload = function (e) {
        try {
          that.fileLoading = true;
          let data = e.target.result;
          //获取xlsx对象
          let workbook = XLSX.read(data, {
            type: "binary",
          });
          if (!sheetName) {
            sheetName = workbook.SheetNames[0];
            that.sheetName = sheetName;
          }
          that.sheetNames = workbook.SheetNames;
          jsonobject_0 = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]);
          that.FileData = jsonobject_0;
          that.fileLoading = false;
          //获取头部
          if (that.FileData.length > 0) {
            that.sourceTitle = [];
            that.sourceTitle.push({ label: "无", value: "0" });
            Object.keys(that.FileData[0]).forEach(function (item) {
              that.sourceTitle.push({ label: item, value: item });
            });
          }
          that.$message.success("数据成功读取" + that.FileData.length + "行");
        } catch (e) {
          that.$message.error(e.message);
          that.fileLoading = false;
        }
      };
      try {
        reader.readAsBinaryString(files);
      } catch (e) {
        that.$message.error(e.message);
        that.fileLoading = false;
        that.sheetNames = [];
        that.sheetName = "";
      }
    },
    clearData() {
      this.FileData = [];
    },
    evtFieldDataRowClass({ row, rowIndex }) {
      if (row.dataSource === "-1") {
        return "";
      } else if (
        (row.dataSource === "" || row.dataSource === "0") &&
        (row.required || row.primaryKey)
      ) {
        row.err = true;
        return "warning-row";
      } else {
        row.err = false;
        return "success-row";
      }
    },
    handleSizeChange: function (size) {
      this.pagesize = size;
    },
    handleCurrentChange: function (currentPage) {
      this.currentPage = currentPage;
    },
    //下一步
    funStepNext() {
      let that = this;
      //验证
      switch (this.stepActive) {
        case 2:
          if (
            this.importTargetData.filter((item) => item.err === true).length > 0
          ) {
            this.$message.error("有必填项目未映射源数据字段，请检查");
            return false;
          }
          break;
        default:
          break;
      }
      //下一步
      this.stepActive++;
      //数据操作
      switch (this.stepActive) {
        case 2:
          //初始化目标字段
          that.importTargetData
            .filter((item) => item.dataSource !== "-1")
            .forEach(function (item) {
              //查找
              let dataSource = that.sourceTitle.filter(
                (row) => row.label === item.label
              );
              if (dataSource.length > 0) {
                item.dataSource = dataSource[0].value;
              } else {
                item.dataSource = "";
              }
            });
          break;
        case 3:
          this.DataValidatePercentage = 0;
          if (!this.apiImportDataValidate) {
            this.$message.error("验证失败，因为未定义验证后台接口API。");
            return;
          }
          this.funImportDataValidate();
          break;
      }
    },
    //上一步
    funStepUp() {
      this.stepActive--;
    },
    //数据验证
    async funImportDataValidate() {
      let that = this;
      that.errDataCnt = 0;
      //每页数量>=20<=100
      let psize = Math.min(
        Math.max(Math.ceil(that.FileData.length / 50), 100),
        20
      );
      //总页数
      let pages = Math.ceil(that.FileData.length / psize);
      that.DataValidate = true;
      that.DataValidatePercentage = 0;
      that.dataList = [];
      for (let i = 1; i <= pages; i++) {
        let pageData = that.FileData.slice((i - 1) * psize, i * psize);
        let submitData = [];
        pageData.forEach(function (item) {
          //本地映射
          let dataitem = {};
          that.importTargetData.forEach(function (col) {
            if (
              col.dataSource !== "0" &&
              col.dataSource !== "-1" &&
              col.dataSource !== ""
            ) {
              //绑定数据
              dataitem[col.prop] = item[col.dataSource];
            } else {
              dataitem[col.prop] = "";
            }
          });
          submitData.push(dataitem);
        });
        let res = await that.apiImportDataValidate(
          JSON.stringify(submitData),
          JSON.stringify(that.importQueryFiled),
          i,
          pages
        );
        that.dataListALL = that.dataList.concat(res.data);
        that.dataList = that.dataListALL;
        that.DataValidatePercentage = parseInt((i / pages) * 100);
      }
      //展示返回数据
      that.currentPage = 1;
      that.errDataCnt = that.dataList.filter(
        (item) => item.status !== "0"
      ).length;
      that.DataValidate = false;
    },
    funFilterData(status) {
      this.currentPage = 1;
      switch (status) {
        case "ok":
          this.dataList = this.dataListALL.filter(
            (item) => item.status === "0"
          );
          break;
        case "err":
          this.dataList = this.dataListALL.filter(
            (item) => item.status !== "0"
          );
          break;
        default:
          this.dataList = this.dataListALL;
      }
    },
    evtFilterCommand(val) {
      this.funFilterData(val);
    },
    //导出数据
    funExportExcel() {
      let headerTitle = [];
      this.importTargetData.forEach(function (item) {
        headerTitle.push(item.prop);
      });
      const header = { header: headerTitle };
      const ws = XLSX.utils.json_to_sheet(this.dataList, header);
      const wb = XLSX.utils.book_new();
      let fileName = "导出数据";
      XLSX.utils.book_append_sheet(wb, ws, fileName);
      XLSX.writeFile(wb, fileName + ".xlsx");
    },
    //导入数据
    async funImportData() {
      let importList = this.dataListALL.filter((item) => item.status === "0");
      if (importList.length === 0) {
        this.$message.error("导入失败，没有正确的数据数据导入。");
        return false;
      }
      if (this.updateType === 1) {
        //返回数据
        this.importLoading = true;
        this.$emit("returnData", importList);
      } else {
        if (!this.apiImportData) {
          this.$message.error("导入失败，因为未定义导入后台接口API。");
          return false;
        }
        let that = this;
        //每页数量>=20<=100
        let psize = Math.min(
          Math.max(Math.ceil(importList.length / 50), 100),
          20
        );
        //总页数
        let pages = Math.ceil(importList.length / psize);
        that.importLoading = true;
        that.DataImportPercentage = 0;
        if (that.importQueryFiled) {
          that.importQuery = JSON.parse(JSON.stringify(that.importQueryFiled));
        } else {
          that.importQuery = {};
        }

        for (let i = 1; i <= pages; i++) {
          let pageData = importList.slice((i - 1) * psize, i * psize);
          let ret = await that.apiImportData(
            JSON.stringify(pageData),
            JSON.stringify(that.importQuery),
            i,
            pages
          );
          if (ret.status !== "success") {
            that.$message.error("导入失败");
            return false;
          }
          that.importQuery = ret.data;
          that.DataImportPercentage = parseInt((i / pages) * 100);
        }
        //that.importLoading = false
        this.$emit("finish", that.importQuery);
      }
    },
    funSetImportPercentage(per) {
      this.DataImportPercentage = per;
      if (per >= 100) {
        this.importLoading = false;
      }
    },
    funClose() {
      this.$emit("close");
    },
  },
};
</script>

<style lang="scss" scoped>
.right-line {
  border-right: 1px dashed #eee;
}

.grid-content {
  height: 52px;
  padding: 20px;
  cursor: pointer;

  &:hover {
    background-color: #f7f7f7;

    .msg {
      color: #666666;
    }
  }

  span {
    float: left;
    width: 100%;
  }

  i {
    margin-right: 3px;
  }

  .title {
    font-size: 22px;
    font-weight: bold;
  }

  .msg {
    color: #999999;
    font-size: 13px;
    margin-top: 5px;
  }
}
</style>
